UnityのiOS向けビルドを別アプリに含んで起動する
概要
最近Unityで遊んでるのだけど、ちょっと思う所あってゴニョゴニョと弄ってみてた。
今回試したのは、iOS向けにビルドしたUnityのアプリパッケージを全く弄らず、
Xcodeで自前作成したアプリケーションから起動してみようぜ、というもの。
追求したい利点としては
・端末へのインストールをもうちょい楽に自動化したい
いろいろとまあ、なんだ、そのままやると大変。
・iOSのネイティブアプリケーション部分のバージョン管理がしやすくなる
本命。
iOSのプロジェクト本体と、まるっと生成されるUnityでのアプリケーション、
従来ならUnityに完全包含されてしまう、iOS側の設定がとっても楽になる。
などなので、決して、非プロ版で起動スプラッシュ外そうぜとかそういうノリでやっている物ではない。
、、プロ版は、、、いいぞ、、、!!
完成系のイメージ
自分で適当に制作したアプリケーションに、任意のUnityのプロジェクト一式を読み込んで、
任意のタイミング、コード上のポイントから、Unity起動~終了、などが扱えるようになる。
手順
①UnityでiOS用にプロジェクトをビルドしておく。プロ版とか、そうでない版のプロジェクトを用意
②所変わって、XcodeでiOS用の新規プロジェクトを用意、ここではSampleProjectって名前にする
ちなみにARCは使用不可。
Unityが吐き出すApplicationがバリバリにAutoreleasePoolとか使ってるので。
③SampleProjectのprefixに設定を追加する
作成したアプリケーションのXcode上でのグループ
SampleProject/Supporting Files/SampleProject-Prefix.pch 箇所に下記を足す。
#ifdef __cplusplus
extern "C" {
#endif
void UnitySendMessage(const char* obj, const char* method, const char* msg);
#ifdef __cplusplus
}
#endif
#define printf_console printf
#define IPHONE_TRAMPOLINE 1
こいつは、Unityのアプリケーションを足した際、主にprintf_consoleの為に使う。
UnitySendMessageも大事だけど。
④下記のframeworkを追加
SystemConfiguration.framework
CoreLocation.framework
MediaPlayer.framework
UIKit.framework
OpenGLES.framework
QuartzCore.framework
OpenAL.framework
libiconv.2.dylib
CFNetwork.framework
AudioToolbox.framework
iAd.framework
CoreMedia.framework
CoreVideo.framework
AVFoundation.framework
CoreGraphics.framework
CoreMotion.framework
GameKit.framework
すべてUnityに含まれているもの。
⑤UnityをBootするクラス UnityBooter を作成する
NSObjectを拡張してクラスを一つ作る。
起動部分でC++を使うため、Obj-C++、拡張子は.mm にする。
この後で、Unityのプロジェクト一式を含むようにするため、
このクラスの初期化メソッドからUnityを起動できるようにしむける。
下記が UnityBooter.mm の内容。
#import "UnityBooter.h"
#import "AppController.h"
#import "RegisterClasses.h"
#import "RegisterMonoModules.h"
static const int constsection = 0;
bool UnityParseCommandLine(int argc, char *argv[]);
@implementation UnityBooter
- (id) initWithApp:(UIApplication * )application withLaunchOptions:(NSDictionary * )launchOptions {
if (self = [super init]) {
RegisterMonoModules();
AppController * unityApp = [[AppController alloc]init];
[unityApp application:application didFinishLaunchingWithOptions:launchOptions];
}
return self;
}
@end
この時点で、下のようなプロジェクトの構成になっているはず。
で、initWithApp メソッドをAppDelegateから適切な引数で呼ぶようにする。
UnityBooter.hにも書いておこう。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
UnityBooter * booter = [[UnityBooter alloc]initWithApp:application withLaunchOptions:launchOptions];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
⑥UnityでiOS用 Device用ビルドを、自作プロジェクトに放り込む
ほんとにそのまま放り込む。
ここでは、Unityから吐き出したiOSアプリ用プロジェクトを、iOSUnityという名前にした。
(Device用に設定したため、Deviceでしか動かないが、過去の記事を参考に何かすると、Simulatorでももちろん動かせる。)
http://sassembla.github.com/Public/2012:12:01%2012-03-18/2012:12:01%2012-03-18.html
一度SampleProject フォルダに放り込んだ後、XcodeからSampleProjectへとaddする。
そのままプロジェクトに含んだ結果。
⑦Unityから持ち込んだ main.mmファイルを、remove reference する
Xcodeグループ内、iOSUnityApp/Classes/main.mm の参照を消す。
mainが2つあると、そもビルドが通らないので、referenceのみでいいからremoveする必要がある。
ここだけはどうしようも無かった。 ファイルを捨てる必要は無い。
⑧C++ Standard Library の設定を、Defaultに変更
Compiler Default に変更する。
⑨Valid Architectures を、armv7 armv7s から、armv7 のみに変更する
Unityで使用しているライブラリが、armv7sに対応してないので、armv7のみをValidなアーキテクチャとして設定する。
(Unityは、ターゲットがarmv7s対象のみ、とか設定したら、7s対応したVersionのライブラリを吐くのかもしれない。未確認。)
⑨Build Active Architecuture Only に No と入力
ビルド時にarmv7のみを設定するようにしたため、この部分がNoでないと矛盾してエラーが出る。
⑩Build Phases に、UnityのDataをアプリケーションビルド時に内部にコピーするスクリプトを追加する
位置 = 実行順序をドラッグして調整
内容として、下記を入力。太字部分はUnityのプロジェクト名。
rm -rf "$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Data"
cp -Rf "$PROJECT_DIR/iOSUnityApp/Data" "$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Data"
if [ "$PLATFORM_NAME" == "iphonesimulator" ]
then cp -f "$PROJECT_DIR/iOSUnityApp"/*.png "$TARGET_BUILD_DIR/$PRODUCT_NAME.app/"
fi
これで、iOSUnityApp内に含まれるDataフォルダが、アプリケーションビルド時に、.app内に含まれるようになる。
これをやらないと、Unityの起動後、シーンデータなどが読み込めずに落ちる。
おまけ①:非プロ版の場合、Applicationに自前で含まれている Supporting Files 下のスプラッシュを消す必要がある
Unityのプロジェクトに含まれているものが使われないと、落ちる。
素晴らしいフェイルセーフ。異論は無い。
アプリケーションの中の SampleProject/Supporting Files の中のpngを削除。
これで、自動的にUnityプロジェクトに含まれるものが使われる。
おまけ②:実機にインストールする場合、一度Xcodeを再起動しないと、Valid Architectures の設定が読み込み直されない。
Xcode終了して再度プロジェクト開けばOK。
以上で、ビルドは通り、実機を繋げば実行できる、、ハズ。
参考までに、Unityのプロジェクトを含まない外装一式をgithubに置いておいた。
https://github.com/sassembla/UnityFreeLocation_SampleProject
起動からボタンを表示するViewをつけて、ボタンが押されたらUnity起動、という遷移のスクリーンショット
めざめたおっさんが走り出す。 時間が戻ってるのはすいません、キャプチャミスった。
非プロ版だと、ちゃんとUnity起動時に powered by Unity のSplashが出る。
ツッコミ等あれば、@toru_inoueまで。